import pygame
from pygame.sprite import Sprite, Group
import queue
from web import mainThread
import time, math


# 定义窗口大小
SCREEN_WIDTH, SCREEN_HEIGHT = 1000, 700
# 外边距 左上右下
MARGINS = (100, 100, 100, 100)
BLOCK = (80, 80)
# 定义预设颜色
BLACK = pygame.Color(0, 0, 0)
WHITE = pygame.Color(255, 255, 255)
RED = pygame.Color(255, 0, 0)
GREEN = pygame.Color(0, 255, 0)
BLUE = pygame.Color(0, 0, 255)
# 定义地形颜色
maps = [
    pygame.Color(192, 192, 192),  # 0 禁用地形
    pygame.Color(0, 153, 102),  # 1 草地
    pygame.Color(204, 153, 153),
    pygame.Color(0, 0, 153),
]
# 定义系统参数
cfg = {"menu": None, "input": [], "act": None}
tcp = {"recv": queue.Queue(), "send": queue.Queue()}


class Baseitem(Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)


class myTrack(Baseitem):  # 轨道类
    def __init__(self, left, top, idx, map_idx):
        super(myTrack, self).__init__()
        self.index = idx
        self.image = pygame.Surface([824, 80])
        self.image.fill(maps[map_idx])
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = left, top
        self.status = map_idx

    def displayTank(self):
        # 调用blit展示
        MainGame.window.blit(self.image, self.rect)


class myCard(Baseitem):  # 卡片类
    def __init__(self, left, top, guid, data):
        super(myCard, self).__init__()
        self.id = data.get("id")
        self.name = data.get("name")
        self.guid = guid
        self.mode = "card"  # 物理类别
        self.status = "ready"
        self.image = pygame.image.load(f"img/{self.name}.png")
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = left, top
        self.dragging = False  # 正在拖动
        # 副本
        self.copy = pygame.image.load(f"img/{self.name}.png")
        self.move_rect = self.copy.get_rect()

    def displayTank(self):
        # 调用blit展示
        MainGame.window.blit(self.image, self.rect)

    def displayCopy(self):
        # 调用blit展示
        MainGame.window.blit(self.copy, self.move_rect)

    def targetBlock(self, pos):
        """计算目标位置块"""
        x, y = math.ceil((pos[0] - 100) / 80) - 1, math.ceil((pos[1] - 100) / 80) - 1
        if x < 0 or x > 12:
            return
        if y < 0 or y > 6:
            return
        track = thread2.findMapsFromGuidState(y)
        if not track:
            return
        print("创建位置: ", x, y)
        data = {
            "act": "buyCard",
            "guid": thread1.guid,
            "data": {
                "id": self.id,
                "name": self.name,
                "guid": self.guid,
                "point": [x, y],
            },
        }
        tcp["send"].put(data)

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.rect.collidepoint(*pygame.mouse.get_pos()):
                self.dragging = True
        elif event.type == pygame.MOUSEBUTTONUP:
            if self.dragging:
                self.targetBlock(event.pos)
            self.dragging = False
            # print("释放位置:", event.pos)
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging:
                self.move_rect.center = event.pos


class myZombie(Baseitem):  # 僵尸类
    def __init__(self, left, top, guid, data):
        super(myZombie, self).__init__()
        self.guid = guid
        self.mode = "zombie"  # 物理类别
        self.data = data

        tool = self.data.get("jewelry")
        if tool and tool.get("name") == "路障":
            self.image = pygame.image.load("img/小僵尸路障.png")
        else:
            self.image = pygame.image.load(f'img/{self.data["name"]}.png')
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = left + MARGINS[0], top + MARGINS[1]

        self.hp = 0

    def displayTank(self):
        # 调用blit展示
        MainGame.window.blit(self.image, self.rect)

    def move(self, point):
        """移动类"""
        self.rect.left = point[0] + MARGINS[0]


class myPlant(Baseitem):  # 植物类
    def __init__(self, left, top, guid, data):
        super(myPlant, self).__init__()
        self.guid = guid
        self.mode = "plant"  # 物理类别
        self.data = data
        self.image = pygame.image.load(f'img/{self.data["name"]}.png')
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = (
            left + MARGINS[0],
            top + MARGINS[1],
        )

    def displayTank(self):
        # 调用blit展示
        MainGame.window.blit(self.image, self.rect)

    def move(self, left, top):
        self.rect.left, self.rect.top = (
            left + MARGINS[0],
            top + MARGINS[1],
        )


class myStar(Baseitem):  # 星星类
    def __init__(self, left, top, guid, data):
        super(myStar, self).__init__()
        self.guid = guid
        self.mode = "star"  # 物理类别
        self.data = data  # 面值
        self.image = pygame.image.load(f"img/star.png")
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = (
            left + 30,
            top * BLOCK[1] + MARGINS[1],
        )

    def displayTank(self):
        # 调用blit展示
        if self.data["hp"] > 0:
            MainGame.window.blit(self.image, self.rect)

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.rect.collidepoint(*pygame.mouse.get_pos()):
                self.sunshine()

    def sunshine(self):
        """收取阳光"""
        data = {"act": "sunshine", "target": self.guid, "data": self.data}
        tcp["send"].put(data)


class mySlug(Baseitem):  # 子弹类
    def __init__(self, left, top, guid, data):
        super(mySlug, self).__init__()
        self.guid = guid
        self.mode = "slug"  # 物理类别
        self.data = data  # 面值
        self.image = pygame.image.load("img/fire_1.png")
        self.rect = self.image.get_rect()  # 根据图片获取区域
        self.rect.left, self.rect.top = (
            left * BLOCK[0] + MARGINS[0],
            top * BLOCK[1] + MARGINS[1] + BLOCK[1] / 2,
        )

    def displayTank(self):
        # 调用blit展示
        if self.data["hp"] > 0:
            MainGame.window.blit(self.image, self.rect)

    def move(self):
        """子弹自动移动"""
        self.rect.left += self.data["move"]
        if self.rect.left > 900:
            self.kill()


# ------------------------------------------------------------------------


class MainGame:
    window = None

    def __init__(self):
        self.isRun = True  # 运行状态
        self.alert = False
        self.status = "wait"  # 游戏状态
        self.maps = None  # 当前关卡
        self.money = 0  # 当前金币
        self.track_y = 100
        self.track = Group()

        self.gear = {}  # 所有对象类-未启用
        self.card_x = 100  # 卡片位置X，y=5
        self.card = Group()
        self.zombie_x = 980
        self.zombie = Group()
        self.plant_x = 100  # 左边距
        self.plant = Group()
        self.star = Group()
        self.slug = Group()

    def stop(self):
        self.isRun = False

    def startGame(self):
        pygame.display.init()  # 加载主窗口
        MainGame.window = pygame.display.set_mode(
            [SCREEN_WIDTH, SCREEN_HEIGHT]
        )  # 设置窗口大小并显示
        pygame.font.init()  # 初始化文本
        # 窗口标题设置
        pygame.display.set_caption("植物大战僵尸")
        # 关闭输入法
        pygame.key.stop_text_input()
        while self.isRun:
            time.sleep(0.1)
            # 颜色填充
            MainGame.window.fill(BLACK)
            # 获取事件
            self.getEvent()
            # 绘制当前金币
            MainGame.window.blit(
                self.getTextSuface("金币:%d" % self.money),
                (10, 5),
            )

            # 检测网络消息
            if not tcp["recv"].empty():
                msg = tcp["recv"].get()
                # print("接收队列:", msg)
                # print(tcp["recv"].qsize())
                if (
                    msg.get("act") == "init"
                    and msg.get("code") == 200
                    and msg.get("guid") == thread1.guid
                ):
                    cfg["act"] = "init"
                    cfg["menu"] = [
                        msg.get("data"),
                    ]
                elif (
                    msg.get("act") == "enter"
                    and msg.get("code") == 200
                    and msg.get("guid") == thread1.guid
                ):
                    cfg["act"] = "enter"
                    cfg["menu"] = [f"加入房间成功", "1  准备就绪"]
                    cfg["input"] = [
                        pygame.K_1,
                    ]
                elif (
                    msg.get("act") == "ready"
                    and msg.get("code") == 200
                    and msg.get("guid") == thread1.guid
                ):
                    cfg["act"] = "ready"
                    cfg["menu"] = [f"准备就绪", "1  取消准备"]
                    cfg["input"] = [
                        pygame.K_1,
                    ]
                elif (
                    msg.get("act") == "wait"
                    and msg.get("code") == 200
                    and msg.get("guid") == thread1.guid
                ):
                    cfg["act"] = "enter"
                    cfg["menu"] = [f"加入房间成功", "1  准备就绪"]
                    cfg["input"] = [
                        pygame.K_1,
                    ]
                elif msg.get("act") == "lock" and msg.get("code") == 200:
                    cfg["act"] = "lock"
                    cfg["menu"] = [
                        f'锁定用户 {msg.get("data")}',
                    ]
                    self.status = "lock"
                elif msg.get("act") == "fight" and msg.get("code") == 200:
                    cfg["act"] = "fight"
                    cfg["menu"] = None
                    self.status = "fight"
                elif msg.get("act") == "money":  # 加载金币
                    self.money = msg.get("data")
                elif msg.get("act") == "maps":  # 加载地图
                    self.maps = msg.get("data")
                    for idx in range(7):
                        self.findMapsFromGuid(idx)
                elif msg.get("act") == "newCard":  # 加载卡片
                    self.findCardFromGuid(
                        msg.get("guid"), msg.get("data"), msg.get("point")
                    )
                elif msg.get("act") == "newZombie":  # 加载僵尸
                    self.findZombieFromGuid(
                        msg.get("guid"), msg.get("data"), msg.get("point")
                    )
                elif msg.get("act") == "move":  # 移动僵尸
                    js = self.findZombieFromGuid(
                        msg.get("guid"), msg.get("data"), msg.get("point")
                    )
                    js.move(msg.get("point"))
                elif msg.get("act") == "newPlant":  # 新的植物
                    zw = self.findPlantFromGuid(
                        msg.get("guid"), msg.get("data"), msg.get("point")
                    )
                elif msg.get("act") == "newStar":  # 星星
                    self.do_newStar(msg.get("guid"), msg.get("data"), msg.get("point"))
                elif msg.get("act") == "firePlant":  # 植物攻击
                    self.do_firePlant(msg.get("guid"), msg.get("data"))
                elif msg.get("act") == "sunShine":  # 收取阳光
                    self.money += msg.get("data")
                    sun = self.onlyFindStar(msg.get("guid"))
                    sun.kill()
                    self.star.remove(sun)
                elif msg.get("act") == "fireSlug":  # 新子弹
                    self.do_newSlug(msg.get("guid"), msg.get("data"), msg.get("point"))

                else:
                    print(msg)
            # 绘制地形
            for track in self.track:
                track.displayTank()

            # 绘制卡片
            for card in self.card:
                card.displayTank()
                if card.dragging:
                    card.displayCopy()

            # 绘制僵尸
            for zombie in self.zombie:
                zombie.displayTank()

            # 绘制植物
            for plant in self.plant:
                plant.displayTank()

            # 绘制星星
            for star in self.star:
                star.displayTank()

            # 绘制子弹
            for slug in self.slug:
                slug.move()
                slug.displayTank()

            # 绘制菜单文字
            menu = cfg.get("menu")
            if menu:
                msg = self.messageShow(menu)
                for surface, pos in msg:
                    MainGame.window.blit(surface, pos)

            # 更新视图
            pygame.display.update()

    def findMapsFromGuidState(self, idx):
        """根据idx查找轨道"""
        for i in self.track:
            if i.index == idx and i.status > 0:
                return i
        else:
            return False

    def findMapsFromGuid(self, idx):
        """根据idx查找轨道"""
        for i in self.track:
            if i.index == idx:
                return i
        else:  # 创建轨道
            n = myTrack(100, self.track_y, idx, self.maps["track"][idx])
            self.track.add(n)
            self.track_y += 80
            return n

    def findCardFromGuid(self, guid, data, point):
        """根据guid查找卡片"""
        for i in self.card:
            if i.guid == guid:
                return i
        else:  # 创建新卡片
            n = myCard(self.card_x + point * 65, 5, guid, data)
            self.card.add(n)
            return n

    def findZombieFromGuid(self, guid, data, point):
        """根据guid查找僵尸 集合"""
        for i in self.zombie:
            if i.guid == guid:
                return i
        else:  # 创建僵尸
            n = myZombie(point[0], point[1], guid, data)
            self.zombie.add(n)
            return n

    def findPlantFromGuid(self, guid, data, point):
        """根据guid查找植物"""
        for i in self.plant:
            if i.guid == guid:
                return i
        else:
            n = myPlant(point[0], point[1], guid, data)
            self.plant.add(n)
            return n

    # --------------------------------------------------------
    def onlyFindPlant(self, guid):
        """根据guid查找植物"""
        for i in self.plant:
            if i.guid == guid:
                return i
        else:
            return None

    def onlyFindStar(self, guid):
        """根据guid查找阳光"""
        for i in self.star:
            if i.guid == guid:
                return i
        else:
            return None

    # --------------------------------------------------------
    def do_newStar(self, guid, data, point):
        """创建星星"""
        print("初始化星星:", guid)
        xx = myStar(point[0], point[1], guid, data)
        self.star.add(xx)

    def do_newSlug(self, guid, data, point):
        """创建子弹"""
        zd = mySlug(point[0], point[1], guid, data)
        self.slug.add(zd)

    def do_firePlant(self, guid, data):
        """植物攻击"""

    # def findZombieFromGuidDict(self, msg):
    #     """根据guid查找僵尸 字典"""
    #     guid = msg.get("guid")
    #     data = msg.get("data")
    #     name = data.get("name")
    #     track = data.get("xy")
    #     tool = data.get("tool")
    #     i = self.zombie.get(guid, None)
    #     if not i:
    #         n = myZombie(track[0], track[1], guid, name, tool)
    #         self.zombie[guid] = n
    #         return n
    #     return i

    def getTextSuface(self, text):
        """显示单行文本"""
        # pygame.font.init()  # 字体初始化
        font = pygame.font.SysFont("kaiti", 16)
        # 绘制文字信息
        textSurface = font.render(text, True, RED)
        return textSurface

    def messageShow(self, textlist=[]):
        """显示文本"""
        # pygame.font.init()
        font = pygame.font.SysFont("SimSun", 20)
        text_surfaces = [font.render(line, True, (0, 255, 0)) for line in textlist]
        text_positions = [
            (5, 400 + i * (text_surfaces[0].get_height() + 5))
            for i, _ in enumerate(textlist)
        ]
        return zip(text_surfaces, text_positions)

    def getEvent(self):
        """获取所有事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # 退出游戏
                self.stop()
            elif event.type == pygame.KEYUP:
                if event.key in cfg.get("input"):  # and event.key == pygame.K_1:
                    # print(0 - (48 - event.key))
                    idx = 0 - (48 - event.key)
                    if cfg.get("act") == "enter":
                        tcp["send"].put(
                            {"act": "ready", "guid": thread1.guid, "data": idx}
                        )
                    elif cfg.get("act") == "ready":
                        tcp["send"].put(
                            {"act": "wait", "guid": thread1.guid, "data": idx}
                        )
                    else:
                        pass
                    cfg["act"] = None
                    cfg["menu"] = None
                    cfg["input"] = []
            else:
                for sprite in self.card:
                    sprite.handle_event(event)
                for sprite in self.star:
                    sprite.handle_event(event)


if __name__ == "__main__":
    print("hello")
    # 网路线程
    thread1 = mainThread(tcp)
    thread1.start()
    thread2 = MainGame()
    thread2.startGame()
    thread1.stop()
    thread1.join()
    print("bye")
